/******************************************************************************
 * Copyright 2022 The Airos Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "v2x_encode_component.h"

#include <sys/time.h>
#include "gflags/gflags.h"

namespace os {
namespace v2x {
namespace protocol {

DEFINE_string(asn_version, "4layer", "v2x message Asn.1 file version");

bool AIROS_COMPONENT_CLASS_NAME(V2xEncodeComponent)::Init() {
  std::string asn_version(FLAGS_asn_version);
  if (asn_version.compare("4layer") == 0) {
    asn_type_ = EnAsnType::CASE_53_2020;
  } else if (asn_version.compare("new_4layer") == 0) {
    asn_type_ = EnAsnType::YDT_3709_2020;
  } else {
    // pass
  }

  return true;
}

bool AIROS_COMPONENT_CLASS_NAME(V2xEncodeComponent)::Proc(
    const std::shared_ptr<const v2xpb::asn::MessageFrame>& frame) {
  if (!frame) {
    AWARN << "frame is nullptr";
    return false;
  }
  auto encode_pb = std::make_shared<os::v2x::device::RSUData>();
  if (!MessageFrame2RsuPb(frame, encode_pb)) {
    AWARN << "message frame to rsupb failed";
    return false;
  }
  Send("/v2x/device/rsu_in", encode_pb);
  return true;
}

bool AIROS_COMPONENT_CLASS_NAME(V2xEncodeComponent)::MessageFrame2RsuPb(
    const std::shared_ptr<const v2xpb::asn::MessageFrame>& frame,
    std::shared_ptr<os::v2x::device::RSUData>& encode_pb) {
  if (!frame || !encode_pb) {
    AWARN << "input is nullptr";
    return false;
  }

  os::v2x::device::RSUDataType data_type;
  switch (frame->payload_case()) {
    case v2xpb::asn::MessageFrame::PayloadCase::kBsmFrame:
      data_type = os::v2x::device::RSU_BSM;
      AINFO << "recv msg pb bsm";
      break;
    case v2xpb::asn::MessageFrame::PayloadCase::kMapFrame:
      data_type = os::v2x::device::RSU_MAP;
      AINFO << "recv msg pb map";
      break;
    case v2xpb::asn::MessageFrame::PayloadCase::kRsmFrame:
      data_type = os::v2x::device::RSU_RSM;
      AINFO << "recv msg pb rsm";
      break;
    case v2xpb::asn::MessageFrame::PayloadCase::kSpatFrame:
      data_type = os::v2x::device::RSU_SPAT;
      AINFO << "recv msg pb spat";
      break;
    case v2xpb::asn::MessageFrame::PayloadCase::kRsiFrame:
      data_type = os::v2x::device::RSU_RSI;
      AINFO << "recv msg pb rsi";
      break;
    default:
      AWARN << "msg type not support ";
      return false;
  }

  std::string str_pb;
  if (!frame->SerializePartialToString(&str_pb)) {
    AWARN << "pb serialize false";
    return false;
  }

  std::string str_asn;
  if (0 > message_frame_pbstr2uper_adapter(str_pb, &str_asn, asn_type_)) {
    AWARN << "pb to asn false";
    return false;
  }

  struct timeval tv;
  gettimeofday(&tv, NULL);
  encode_pb->set_time_stamp(
      static_cast<uint64_t>(tv.tv_sec * 1000 + tv.tv_usec / 1000));
  encode_pb->set_data((const void*)(str_asn.data()), (size_t)(str_asn.size()));
  encode_pb->set_type(data_type);

  return true;
}

}  // namespace protocol
}  // namespace v2x
}  // namespace os